package com.ganmiao.exception;

import com.ganmiao.resp.MobBaseRes;
import com.ganmiao.resp.ResponseCode;
import lombok.extern.log4j.Log4j2;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

@Lazy
@RestControllerAdvice
@Log4j2
public class GlobalExceptionHandler {
    @ExceptionHandler(value = Exception.class) // 该注解声明异常处理方法
    public ExceptionResponse GlobalExceptionHandler(HttpServletRequest request, Exception ex) throws Exception {
        String errorMsg = null;
        String reqUrl = request.getRequestURL().toString();
        String queryString = request.getQueryString();
        String clientIP = request.getRemoteAddr();
        String reqUri = request.getRequestURI();
        String method = request.getMethod();
        String paramsString = String.format(
                " request method[%s], url=【%s】 \r\n queryString=【%s】\r\n clientIP【%s】  \r\n request reqUri=【%s】 \r\n",
                method, reqUrl, queryString, clientIP, reqUri);

        if (ex instanceof AbstractBusinessException) {
            AbstractBusinessException bException = (AbstractBusinessException) ex;
            errorMsg = String.format("捕获自定义业务异常，错误信息：code【%d】 desc【%s】 with requestInfo【%s】", bException.getResponseCode(),
                    bException.getMessage(), paramsString);
            log.error(errorMsg, ex);
            return new ExceptionResponse(bException);
        } else {
            errorMsg = String.format("捕获未知异常：code【%d】 desc【%s】 with queryString【%s】：",
                    ResponseCode.SERVER_EXCEPTION.getCode(), ResponseCode.SERVER_EXCEPTION.getDesc(), paramsString);
            log.error(errorMsg, ex);
            return new ExceptionResponse(ResponseCode.SERVER_EXCEPTION);
        }
    }

    /**
     * 自定义验证异常
     * MethodArgumentNotValidException 方法参数无效异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST) //设置状态码为 400
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public MobBaseRes paramExceptionHandler(MethodArgumentNotValidException e) {
        BindingResult exceptions = e.getBindingResult();
        // 判断异常中是否有错误信息，如果存在就使用异常中的消息，否则使用默认消息
        if (exceptions.hasErrors()) {
            List errors = exceptions.getAllErrors();
            if (!errors.isEmpty()) {
                // 这里列出了全部错误参数，按正常逻辑，只需要第一条错误即可
                FieldError fieldError = (FieldError) errors.get(0);
                List<String> list = new ArrayList<>();
                for (Object error : errors) {
                    FieldError err = (FieldError) error;
                    list.add(err.getDefaultMessage());
                }
                return new MobBaseRes(ResponseCode.FAIL.getCode(), list.toString());
            }
        }
        return new MobBaseRes(ResponseCode.FAIL.getCode(), "请求参数错误");
    }

    @ResponseBody
    @ExceptionHandler(value = BindException.class)
    public MobBaseRes bindException(Exception e) {
        if (e instanceof BindException) {
            BindException exs = (BindException) e;
            List<FieldError> fieldErrors = exs.getFieldErrors();
            List<String> list = new ArrayList<>();
            for (FieldError item : fieldErrors) {
                list.add(item.getDefaultMessage());
            }
            return new MobBaseRes(ResponseCode.FAIL.getCode(), list.toString());
        }
        return new MobBaseRes(ResponseCode.FAIL.getCode(), "请求参数错误");
    }

}
